package com.blast.manager.blast.presenter

import android.content.Context
import android.text.TextUtils
import com.alibaba.fastjson.JSONArray
import com.blast.manager.bean.ReadyErrorModel
import com.blast.manager.blast.BlastActivity
import com.wxl.common.AppContext
import com.wxl.common.base.AbsActivity
import com.wxl.common.bean.ScanLeiGuanBean
import com.wxl.common.http.CommonHttpUtil
import com.wxl.common.room.entity.*
import com.wxl.common.room.helper.DBHelper
import com.wxl.common.serialport.*
import com.wxl.common.util.DateUtils
import com.wxl.common.util.ObservableUtil
import com.wxl.common.util.Toll
import com.wxl.common.viewmodel.AbsPresenter
import io.reactivex.ObservableOnSubscribe
import java.util.*

class BlastSerialPresenter : AbsPresenter() {

    private lateinit var context: Context
    private var mCurrentDetonatorNum = 0
    private var mDelayInputCount = 0
    private val lgs = arrayListOf<LeiGuanEntity>()
    private val lgsBlastError = arrayListOf<LeiGuanEntity>()
    private val lgsBlastData = arrayListOf<LeiGuanEntity>()
    val notAuthArray = arrayListOf<LeiGuanEntity>()
    val notMatchArray = arrayListOf<LeiGuanEntity>()
    val notChargeArray = arrayListOf<LeiGuanEntity>()
    val blastRecords = arrayListOf<BlastRecordEntity>()

    override fun onCreated(vararg args: Any) {
        context = args[0] as Context
        SerialPortManager.openOnlyPort(object : SerialPortManager.Companion.OpenPortCallback {
            override fun onOpenPort(state: Int) {
                if (state != 0) {
                    Toll.toll("串口打开失败！")
                    (context as AbsActivity).finish()
                } else {
                    sendAutoUnderData()
                }
            }
        })
    }


    /**
     * 发送自动下传数据
     */
    private fun sendAutoUnderData() {
        if (AppContext.appContext.isAutoUnderPlan()) {
            val data = AppContext.appContext.getAutoUnderData()
            if (!TextUtils.isEmpty(data)) {
                SerialPortManager.sendHexData(data)
            }
        }
    }


    /**
     * 写入延时下传
     */
    private fun sendDelay(callback: OnAuthDelayCallback) {
        callback.onChargeProgress(50, "正在写入延时...", 100)
        val isOpenInputDelayData = AppContext.appContext.getIsOpenInputDelayData()
        Serials.registerSingleStartHexSerial(CmdCode.DELAY_INPUT_OK_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                mDelayInputCount = 0
                (context as BlastActivity).addLog("充电起爆", 0, "正在写入验证")
                queryDelayProveProgress(callback)
            }
        })
        Serials.registerSingleStartHexSerial(CmdCode.DELAY_INPUT_E_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                callback.onChargeProgressError("写入延时失败...")
            }
        })
        SerialPortManager.send(CmdCode.DELAY_INPUT_CMD + if (isOpenInputDelayData) "01" else "00")
    }

    /**
     * 查询写入延时进度
     */
    private fun queryDelayProveProgress(callback: OnAuthDelayCallback) {
        SerialD.registerDelayProgressQuery(object : Serial() {
            override fun loadReceiveData(data: String) {
                parseQueryProgress(data, callback, true)
            }
        })
        SerialPortManager.send(CmdCode.KZB_QUERY_LG_INFO_CMD)
    }

    /**
     * 发送授权验证
     */
    fun sendAuthProve(callback: OnAuthDelayCallback) {
        callback.onChargeProgress(0, "正在进行授权验证...", 100)
        Serials.registerSingleStartHexSerial(CmdCode.AUTH_OK_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                callback.onChargeProgress(1, "正在进行授权验证...", 100)
                queryAuthProveProgress(callback)
            }
        })
        Serials.registerSingleStartHexSerial(CmdCode.AUTH_E_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                callback.onChargeProgressError("授权验证失败！")
            }
        })
        SerialPortManager.send(CmdCode.AUTH_CMD)
    }


    /**
     * 发送授权验证进度查询
     */
    private fun queryAuthProveProgress(callback: OnAuthDelayCallback) {
        SerialD.registerAuthProgressQuery(object : Serial() {
            override fun loadReceiveData(data: String) {
                parseQueryProgress(data, callback, false)
            }
        })
        SerialPortManager.send(CmdCode.KZB_QUERY_LG_INFO_CMD)
    }

    /**
     * 解析进度
     */
    private fun parseQueryProgress(
        data: String,
        callback: OnAuthDelayCallback,
        isDelay: Boolean
    ) {
        if (data.length > 36) {
            val scanResult = ScanLeiGuanBean.parse(data)
            if (isDelay) {
                mDelayInputCount++
                callback.onChargeProgress(
                    scanResult.progress,
                    "正在进行写入验证...($mDelayInputCount)",
                    100
                )
            } else {
                callback.onChargeProgress(scanResult.progress, "正在进行授权验证...", 101)
            }
            callback.onVoltageElectricChanged(scanResult.mVoltage, scanResult.mElectric)
            if (isDelay) {
                if (scanResult.progress < 100) {
                    queryDelayProveProgress(callback)
                } else {
                    callback.onAuthDelayResult()
                }
            } else {
                if (scanResult.progress < 100) {
                    queryAuthProveProgress(callback)
                } else {
                    sendDelay(callback)
                }
            }
        } else {
            callback.onChargeProgressError("授权验证进度解析失败！")
        }
    }


    /**
     * 充电
     */
    fun charge(callback: OnChargeCallback) {
        callback.onChargeProgress(0, "发送充电信息...", 100)
        Serials.registerSingleStartHexSerial(CmdCode.BLAST_CHARGE_OK_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                callback.onChargeProgress(2, "查询充电状态...", 100)
                mDelayInputCount = 0
                (context as BlastActivity).addLog("充电起爆", 0, "开始充电")
                queryChargeState(callback)
            }
        })
        Serials.registerSingleStartHexSerial(CmdCode.BLAST_CHARGE_E_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                callback.onChargeProgressError("起爆充电失败！")
            }
        })
        SerialPortManager.send(CmdCode.BLAST_CHARGE_CMD)
    }


    /**
     * 查询充电状态
     */
    private fun queryChargeState(callback: OnChargeCallback) {
        SerialD.registerChargeQuery(object : Serial() {
            override fun loadReceiveData(data: String) {
                parseQueryChargeData(data, callback)
            }
        })
        SerialPortManager.send(CmdCode.KZB_QUERY_LG_INFO_CMD)
    }

    /**
     * 解析查询数据
     */
    private fun parseQueryChargeData(data: String, callback: OnChargeCallback) {
        if (data.length > 36) {
            val scanResult = ScanLeiGuanBean.parse(data)
            callback.onVoltageElectricChanged(scanResult.mVoltage, scanResult.mElectric)
            // val number = Integer.valueOf(data.substring(24, 28), 16)
            if (scanResult.mElectric == 0 && scanResult.mVoltage == 0) {//充电异常，读取控制板数据
                lgs.clear()
                mCurrentDetonatorNum = 0
                callback.onChargeProgress(43, "读取控制板信息...", 100)
                (context as BlastActivity).addLog("充电起爆", 0, "充电异常，读取控制板信息")
                sendReadControlData(callback)
            } else {
                if (scanResult.progress < 100) {
                    val p = scanResult.progress * 40 / 100 + 2
                    mDelayInputCount++
                    callback.onChargeProgress(p, "查询充电状态...($mDelayInputCount)", 100)
                    queryChargeState(callback)
                } else {//读控制板数据
                    lgs.clear()
                    mCurrentDetonatorNum = 0
                    callback.onChargeProgress(43, "读取控制板信息...", 100)
                    (context as BlastActivity).addLog("充电起爆", 100, "读取控制板信息")
                    sendReadControlData(callback)
                }
            }
        } else {
            callback.onChargeProgressError("解析循环查询控制板数据失败！")
        }
    }

    /**
     * 读控制板数据
     */
    private fun sendReadControlData(callback: OnChargeCallback) {
        Serials.registerSingleStartHexSerial(CmdCode.KZB_READ_LG_INFO_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                parseReadControlData(data, callback)
            }
        })
        val m = SerialUtil.getCurrentDetonatorNum(mCurrentDetonatorNum)
        SerialPortManager.send(CmdCode.KZB_READ_LG_INFO_CMD + m)
    }

    /**
     * 解析读取控制板数据
     */
    private fun parseReadControlData(data: String, callback: OnChargeCallback) {
        if (data.length > 54) {
            val item = LeiGuanEntity.parse(data)
            lgs.add(item)
            if (mCurrentDetonatorNum < item.total - 1) {
                mCurrentDetonatorNum++
                val p = 40 * mCurrentDetonatorNum / item.total + 43
                callback.onChargeProgress(p, "读取控制板信息...", 100)
                sendReadControlData(callback)
            } else {
                checkChargeResult(callback)
            }
        } else {
            callback.onChargeProgressError("解析读取控制板数据失败！")
        }
    }

    /**
     * 检查结果
     */
    private fun checkChargeResult(callback: OnChargeCallback) {
        notAuthArray.clear()
        notMatchArray.clear()
        notChargeArray.clear()
        (context as BlastActivity).addLog("充电起爆", 0, "检查充电结果")
        callback.onChargeProgress(98, "检查充电结果...", 100)
        ObservableUtil.doNext(ObservableOnSubscribe {
            val error = arrayListOf<ReadyErrorModel>()
            lgs.forEach {
                if (!TextUtils.isEmpty(it.state)) {
                    if (TextUtils.equals("0", it.state.toCharArray()[5].toString())
                        || TextUtils.equals("0", it.state.toCharArray()[6].toString())
                    ) {
                        notMatchArray.add(it)
                    }

                    if (TextUtils.equals("0", it.state.toCharArray()[0].toString())) {
                        notChargeArray.add(it)
                    }

                    if (TextUtils.equals("0", it.state.toCharArray()[1].toString())) {
                        notAuthArray.add(it)
                    }
                }
            }

            if (notMatchArray.isNotEmpty()) {
                val e = ReadyErrorModel()
                e.des = notMatchArray.size.toString()
                e.title = "雷管不匹配"
                e.widget = "发"
                error.add(e)
                (context as BlastActivity).addLog("充电起爆", 0, "雷管不匹配${error.size}发")
            }

            if (notAuthArray.isNotEmpty()) {
                val e = ReadyErrorModel()
                e.des = notAuthArray.size.toString()
                e.title = "授权验证失败"
                e.widget = "发"
                error.add(e)
                (context as BlastActivity).addLog("充电起爆", 0, "授权验证失败${error.size}发")
            }

            if (notChargeArray.isNotEmpty()) {
                val e = ReadyErrorModel()
                e.des = notChargeArray.size.toString()
                e.title = "雷管充电异常"
                e.widget = "发"
                error.add(e)
                (context as BlastActivity).addLog("充电起爆", 0, "雷管充电异常${error.size}发")
            }
            it.onNext(error)
        }, object : ObservableUtil.Companion.OnNextCallback<List<ReadyErrorModel>>() {
            override fun onNext(t: List<ReadyErrorModel>) {
                if (t.isNotEmpty()) {
                    callback.onChargeResultError(t, notMatchArray, notAuthArray, notChargeArray)
                } else {
                    callback.onChargeResult()
                }
            }
        })
    }


    /**
     * 爆破
     */
    fun blast(time: Int, callback: OnBlastCallback) {
        Serials.registerSingleStartHexSerial(CmdCode.BLAST_OK_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                if (time == 0) {
                    val maxDelay = findMaxDelay()
                    (context as BlastActivity).addLog("起爆", 50, "正在爆破")
                    callback.onBlastProgress(50, "正在爆破,读取起爆结果...", 100)
                    queryBlastResult(2 * maxDelay + System.currentTimeMillis(), callback)
                }
            }
        })
        Serials.registerSingleStartHexSerial(CmdCode.BLAST_E_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                mCurrentDetonatorNum = 0
                lgsBlastError.clear()
                (context as BlastActivity).addLog("起爆", 100, "起爆失败")
                blastErrorReadControlData(false, "起爆失败", callback, false)
            }
        })
        (context as BlastActivity).addLog("起爆", time, "起爆倒计时$time")
        SerialPortManager.send(CmdCode.BLAST_CMD + "0" + time)
    }

    /**
     * 找最大延时
     */
    private fun findMaxDelay(): Int {
        var max = 0
        DBHelper.queryLeiGuanEntity(object :
            ObservableUtil.Companion.OnNextCallback<List<LeiGuanEntity>>() {
            override fun onNext(t: List<LeiGuanEntity>) {
                lgsBlastData.clear()
                lgsBlastData.addAll(t)
                t.forEach {
                    if (max < it.delay.toInt()) {
                        max = it.delay.toInt()
                    }
                }
            }
        })
        return max
    }

    /**
     * 循环查询起爆结果
     */
    private fun queryBlastResult(maxDelay: Long, callback: OnBlastCallback) {
        SerialD.registerBlastProgressQuery(object : Serial() {
            override fun loadReceiveData(data: String) {
                parseBlastProgress(data, maxDelay, callback)
            }
        })
        SerialPortManager.send(CmdCode.KZB_QUERY_LG_INFO_CMD)
    }


    /**
     * 解析爆破查询数据
     */
    private fun parseBlastProgress(data: String, maxDelay: Long, callback: OnBlastCallback) {
        if (data.length >= 36) {
            val result = ScanLeiGuanBean.parse(data)
            callback.onVoltageElectricChanged(result.mVoltage, result.mElectric)
            if (result.progress < 100) {
                // 雷管起爆状态 0 正常，1 雷管使能异常，中止起爆，中止充电，2 雷管数量不对，中止起爆, 3 雷管状态错误，中止起爆, 4 起爆状态错误，中止起爆
                callback.onBlastProgress(result.progress * 50 / 100 + 50, "正在爆破,读取起爆结果...", 100)
                // Loog.e("maxDelay${maxDelay+ 2000}  currentTimeMillis:${System.currentTimeMillis()}")
                if (System.currentTimeMillis() > maxDelay + 8000) {
                    (context as BlastActivity).addLog(
                        "起爆",
                        result.progress,
                        data.substring(10, 12),
                        "起爆返回超时"
                    )
                    callback.onBlastProgressError("起爆返回超时...", lgsBlastData)
                } else {
                    if (result.stateCode == 0) {
                        queryBlastResult(maxDelay, callback)
                    } else {
                        (context as BlastActivity).addLog(
                            "起爆",
                            result.progress,
                            data.substring(10, 12),
                            result.stateCode.toString(),
                            "爆破失败"
                        )
                        val e = checkBlastErrorStr(result.stateCode)
                        mCurrentDetonatorNum = 0
                        lgsBlastError.clear()
                        blastErrorReadControlData(false, e, callback, false)
                    }
                }
            } else {
                (context as BlastActivity).addLog(
                    "起爆",
                    result.progress,
                    data.substring(10, 12),
                    result.stateCode.toString(),
                    if (result.stateCode == 0) "爆破成功" else checkBlastErrorStr(result.stateCode)
                )
                callback.onBlastProgress(
                    99,
                    if (result.stateCode == 0) "爆破成功..." else checkBlastErrorStr(result.stateCode),
                    100
                )
                mCurrentDetonatorNum = 0
                lgsBlastError.clear()
                blastErrorReadControlData(
                    result.stateCode == 0,
                    if (result.stateCode == 0) "爆破成功" else checkBlastErrorStr(result.stateCode),
                    callback,
                    true
                )
            }
        }
    }


    /**
     * 起爆发生错误，读取控制板数据
     */
    private fun blastErrorReadControlData(
        isSuccess: Boolean,
        e: String,
        callback: OnBlastCallback,
        isBlockLock: Boolean
    ) {
        if (isBlockLock) {
            callback.onBlastBlockLockProgress(
                99,
                "${e},${if (isSuccess) "正在读取起爆结果($mCurrentDetonatorNum)" else "正在读取失败信息($mCurrentDetonatorNum)"}...",
                100
            )
        } else {
            callback.onBlastProgress(
                99,
                "${e},${if (isSuccess) "正在读取起爆结果($mCurrentDetonatorNum)" else "正在读取失败信息($mCurrentDetonatorNum)"}...",
                100
            )
        }
        if (isSuccess) {
            blastRecords.clear()
            if(isBlockLock){
                callback.onBlastBlockLockProgress(99, "正在保存爆破日志...", 100)
            } else {
                callback.onBlastProgress(99, "正在保存爆破日志...", 100)
            }
            makeBlastRecord(object : ObservableUtil.Companion.OnNextCallback<Boolean>() {
                override fun onNext(t: Boolean) {
                    callback.onBlastProgress(100, "保存爆破日志完成...", 100)
                    callback.onBlastResult(blastRecords)
                }
            })
        } else {
            Serials.registerSingleStartHexSerial(CmdCode.KZB_READ_LG_INFO_ASK, object : Serial() {
                override fun loadReceiveData(data: String) {
                    (context as BlastActivity).addLog("起爆", 0, "读取起爆结果")
                    parseBlastErrorReadControlData(data, isSuccess, e, callback, isBlockLock)
                }
            })
            val m = SerialUtil.getCurrentDetonatorNum(mCurrentDetonatorNum)
            SerialPortManager.send(CmdCode.KZB_READ_LG_INFO_CMD + m)
        }
    }


    /**
     * 解析爆破错误结果数据
     */
    private fun parseBlastErrorReadControlData(
        data: String,
        isSuccess: Boolean,
        e: String,
        callback: OnBlastCallback,
        isBlockLock: Boolean
    ) {
        if (data.length > 40) {
            val item = LeiGuanEntity.parse(data)
            lgsBlastError.add(item)
            if (mCurrentDetonatorNum < item.total - 1) {
                mCurrentDetonatorNum++
                blastErrorReadControlData(isSuccess, e, callback, isBlockLock)
            } else {
                if (isSuccess) {
                    //
                } else {
                    (context as BlastActivity).addLog("起爆", 0, "爆破失败")
                    callback.onBlastProgressError("爆破失败...", lgsBlastError)
                }
            }
        }
    }


    /**
     * 设置采集器信息,保存爆破日志
     */
    private fun makeBlastRecord(callback: ObservableUtil.Companion.OnNextCallback<Boolean>) {
        ObservableUtil.doNext(ObservableOnSubscribe { oos ->
            val blastId = System.currentTimeMillis().toString()
            val blastTime = DateUtils.getNowTime()
            lgsBlastData.forEach {
                lgsBlastError.forEach { el ->
                    if (TextUtils.equals(el.UID, it.UID)) {
                        el.collectorNumber = it.collectorNumber
                    }
                }
                it.blastId = blastId
                it.blastTime = blastTime
            }
            makeBlastRecordEntity(blastId, blastTime, lgsBlastData.size, Runnable {
                DBHelper.updateLeiGuan(object : ObservableUtil.Companion.OnNextCallback<Boolean>() {
                    override fun onNext(t: Boolean) {
                        oos.onNext(true)
                    }
                }, *lgsBlastData.toTypedArray())
            })
        }, callback)
    }


    /**
     * 生成爆破记录
     */
    private fun makeBlastRecordEntity(
        blastId: String,
        blastTime: String?,
        total: Int,
        run: Runnable
    ) {
        val record = BlastRecordEntity()
        record.blastId = blastId
        record.blastTime = blastTime
        record.blastTotalNumber = total
        record.latitude = AppContext.appContext.getLat()
        record.longitude = AppContext.appContext.getLon()
        ObservableUtil.doNext(ObservableOnSubscribe { oos ->
            val list = JSONArray.parseArray(
                JSONArray.toJSONString(lgsBlastData),
                LeiGuanBlastEntity::class.java
            ) as ArrayList<LeiGuanBlastEntity>
            DBHelper.insertBlastedLeiGuan(object :
                ObservableUtil.Companion.OnNextCallback<Boolean>() {
                override fun onNext(t: Boolean) {
                    oos.onNext(true)
                }
            }, *list.toTypedArray())
        }, object : ObservableUtil.Companion.OnNextCallback<Boolean>() {
            override fun onNext(t: Boolean) {
                insertBlastRecord(record, run)
            }
        })
    }


    /**
     * 保存爆破记录
     */
    private fun insertBlastRecord(record: BlastRecordEntity, run: Runnable) {
        DBHelper.queryContract(object :
            ObservableUtil.Companion.OnNextCallback<List<ContractInfoEntity>>() {
            override fun onNext(t: List<ContractInfoEntity>) {
                if (t.isNotEmpty()) {
                    record.contractId = t[0].contractid
                    record.contractName = t[0].contractname
                    record.projectName = t[0].projectname
                    record.projectNumber = t[0].projectnumber
                }
                CommonHttpUtil.getDetonatorInfo(object :
                    ObservableUtil.Companion.OnNextCallback<DetonatorEntity>() {
                    override fun onNext(t: DetonatorEntity) {
                        record.buydept = t.buydept
                        record.deviceId = t.num
                        blastRecords.add(record)
                        DBHelper.insertBlastRecord(object :
                            ObservableUtil.Companion.OnNextCallback<Boolean>() {
                            override fun onNext(t: Boolean) {
                                run.run()
                            }
                        }, record)
                    }
                })
            }
        })
    }

    /**
     * 返回起爆失败原因
     */
    private fun checkBlastErrorStr(stateCode: Int): String {
        when (stateCode) {
            1 -> {
                return "雷管使能异常"
            }
            2 -> {
                return "雷管数量不对"
            }
            3 -> {
                return "雷管状态错误"
            }
            4 -> {
                return "起爆状态错误"
            }
        }
        return "起爆发生未知错误"
    }


    /**
     * 关电
     */
    fun closeElectric(callback: ObservableUtil.Companion.OnNextCallback<Boolean>) {
        Serials.registerSingleStartHexSerial(CmdCode.CLOSE_ELECTRIC_OK_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                callback.onNext(true)
            }
        })
        Serials.registerSingleStartHexSerial(CmdCode.CLOSE_ELECTRIC_E_ASK, object : Serial() {
            override fun loadReceiveData(data: String) {
                callback.onNext(false)
            }
        })
        SerialPortManager.send(CmdCode.CLOSE_ELECTRIC_CMD)
    }

    override fun onDestroy() {
        super.onDestroy()
        Serials.unRegisterSingleStartHexSerial(CmdCode.CLOSE_ELECTRIC_OK_ASK)
        Serials.unRegisterSingleStartHexSerial(CmdCode.CLOSE_ELECTRIC_E_ASK)
        //SerialPortManager.close()
        //SerialPortManager.closePower()
        SerialPortManager.cancelIntervalWork()
        SerialD.unRegisterChargeQuery()
        SerialD.unRegisterAuthProgressQuery()
        SerialD.unRegisterDelayProgressQuery()
        SerialD.unRegisterBlastProgressQuery()
    }


    interface OnChargeCallback {
        fun onChargeResult()
        fun onChargeProgress(p: Int, sub: String, max: Int)
        fun onVoltageElectricChanged(mVoltage: Int, mElectric: Int)
        fun onChargeProgressError(sub: String)
        fun onChargeResultError(
            error: List<ReadyErrorModel>,
            notMatchArray: List<LeiGuanEntity>,
            notAuthArray: List<LeiGuanEntity>,
            notChargeArray: List<LeiGuanEntity>
        )
    }


    interface OnAuthDelayCallback {
        fun onAuthDelayResult()
        fun onChargeProgress(p: Int, sub: String, max: Int)
        fun onVoltageElectricChanged(mVoltage: Int, mElectric: Int)
        fun onChargeProgressError(sub: String)
    }

    interface OnBlastCallback {
        fun onBlastResult(blastRecords: List<BlastRecordEntity>)
        fun onBlastProgress(p: Int, sub: String, max: Int)
        fun onBlastBlockLockProgress(p: Int, sub: String, max: Int)
        fun onVoltageElectricChanged(mVoltage: Int, mElectric: Int)
        fun onBlastProgressError(e: String, blastError: List<LeiGuanEntity>)
    }
}